#ifndef STATE_H
#define STATE_H
#include <Vector>
#include "StateContext.h"
#include "foundation.h"
class State
{
public:
	virtual void execute()=0;
	virtual void execute(StateContext* sc1, Player &player)=0;
	vector<int> getPossibleMoves(Player &player){
		vector<int> possibleActiveMoves;
		for (int i = 0; i < MAX_GAME_POSITIONS; i++)
		{
			if (GameData()->board.IsPieceOnTop(player.piece, i))
				possibleActiveMoves.push_back(i);
		}
		return possibleActiveMoves;
	}
	bool trampolinable(Player& player){
		vector<int> possibleActiveMoves = getPossibleMoves(player);
		for (int i = 0; i < (int)possibleActiveMoves.size(); i++){
			if (canTrampoline(i, player))
				return true;
		}
		return false;
	}
	//Check if the piece at position i can hit the trampoline; return 1 if yes, 0 if no
	int canTrampoline(int i, Player &player){
	//vector<int> possibleActiveMoves = getPossibleMoves(player);
	if (GameData()->board.GetSizeOfStack(i) + i == LOTUS_TRAMPOLINE)
		return 1;
	return 0;
	}
	//Check if there are any pieces that can trampoline; if so, return the index of the one furthest from the trampoline
	//if none, return -1
	int getFurthestTrampoline(Player &player){
	vector<int> possibleMoves = getPossibleMoves(player);
	if (!possibleMoves.empty()){
	for (int i= 0; i<(int)possibleMoves.size(); i++){
		if (canTrampoline(possibleMoves.at(i), player) == 1)
			return possibleMoves.at(i);
	}
	}
	return -1;
	}	
	//Check if the piece at position i can exit the gameboard
	//returns 1 if the piece can exit, 0 otherwise
	int canExit(int i){
	if (GameData()->board.GetSizeOfStack(i) + i > MAX_GAME_POSITIONS){
		return 1;
	}
	return 0;
	}
	bool exitable(Player& player){
	vector<int> possibleMoves = getPossibleMoves(player);
	if (!possibleMoves.empty()){
	for (int i=(int)possibleMoves.size()-1; i>-1; i--){
		if (canExit(possibleMoves.at(i)) == 1)
			return true;
	}
	}
	return false;
	}
	//Retrieve the player's piece that is closest to the exit
	//return -1 if all covered?
	int closestToExit(Player &player){
	vector<int> possibleMoves = getPossibleMoves(player);
	if (!possibleMoves.empty()){
	for (int i=(int)possibleMoves.size()-1; i>-1; i--){
		if (canExit(possibleMoves.at(i)) == 1)
			return possibleMoves.at(i);
	}
	}
	return -1;

	}
	//Return true if all of a player's pieces are covered, else false
	bool allPiecesCovered(Player &player){
	vector<int> possibleMoves = getPossibleMoves(player);
	return possibleMoves.empty();
	}
	//Get the location of the piece that can move to the highest stack
	//return -1 if some error
	int makesHighestStack(Player &player){
	vector<int> possibleMoves = getPossibleMoves(player);
	int highest= 0;
	int highestPos = -1;
	if (!possibleMoves.empty()){
		for (int i= 0; i<(int)possibleMoves.size(); i++){
			//if the size of the stack located at (the size of the stack of i + the location of i) is the highest
			if ((GameData()->board.GetSizeOfStack(GameData()->board.GetSizeOfStack(possibleMoves.at(i) + possibleMoves.at(i)))) > highest){
				highest = GameData()->board.GetSizeOfStack(GameData()->board.GetSizeOfStack(possibleMoves.at(i) + possibleMoves.at(i)));
				highestPos = possibleMoves.at(i);
			}
		}
	}
	return highestPos;
}
	//Returns true if we can setup a trampoline
	bool canSetupTrampoline(Player &player){
		vector<int> possibleActiveMoves = getPossibleMoves(player);
		//check if sizestack(i + sizestack(i) + 1) == trampoline
		//if (i + sizestack(i)) + sizestack(i + sizestack(i)) + 1 (when i moves there) == trampoline position
		//i+sizestack(i) is the position i will be in; the size of that stack will be then sizestack(i + sizestack(i)) + 1
		for (int i= 0; i<(int)possibleActiveMoves.size(); i++){
		if(possibleActiveMoves.at(i) + GameData()->board.GetSizeOfStack(possibleActiveMoves.at(i)) + GameData()->board.GetSizeOfStack(possibleActiveMoves.at(i) + GameData()->board.GetSizeOfStack(possibleActiveMoves.at(i))) + 1 == LOTUS_TRAMPOLINE){
			return true;
		}
		}
		return false;
	}
	//Checks if an index i can trampoline next turn
	bool canTrampolineNextTurn(int i, Player &player){
		//check if sizestack(i + sizestack(i) + 1) == trampoline
		//if (i + sizestack(i)) + sizestack(i + sizestack(i)) + 1 (when i moves there) == trampoline position
		//i+sizestack(i) is the position i will be in; the size of that stack will be then sizestack(i + sizestack(i)) + 1
		if(i + GameData()->board.GetSizeOfStack(i) + GameData()->board.GetSizeOfStack(i + GameData()->board.GetSizeOfStack(i)) + 1 == LOTUS_TRAMPOLINE){
			return true;
		}
		return false;
	}
	//Returns the index of the piece furthest from the trampoline that can trampoline next turn if it stacks this turn
	//returns -1 if some issue
	int setupTrampoline(Player& player){
		vector<int> possibleActiveMoves = getPossibleMoves(player);
		for (int i= 0; i<(int)possibleActiveMoves.size(); i++){
			if (canTrampolineNextTurn(possibleActiveMoves.at(i), player))
				return possibleActiveMoves.at(i);
		}
		return -1;
	}
	//return true if all of our pieces are singular - that is, they are not at the top of a stack higher than 2.
	bool singular(Player &player){
		vector<int> possibleMoves = getPossibleMoves(player);
		if (!possibleMoves.empty()){
			for (int i= 0; i<(int)possibleMoves.size(); i++){		
				if (GameData()->board.GetSizeOfStack(possibleMoves.at(i)) > 1)
					return false;
			}
		}
		return true;
	}
};

class StateOne: public State
{
public:
	void execute();
	void execute(StateContext* sc1, Player &player);
};

class StateTwo: public State
{
public:
	void execute();
	void execute(StateContext* sc1, Player &player);
};

class StateThree: public State
{
public:
	void execute();
	void execute(StateContext* sc1, Player &player);
};

class StateFour: public State
{
public:
	void execute(StateContext* sc1, Player &player);
	void execute();
};

class StateFive: public State
{
public:
	void execute(StateContext* sc1, Player &player);
	void execute();
};

class StateSix: public State
{
public:
	void execute(StateContext* sc1, Player &player);
	void execute();
};

class StateSeven: public State
{
public:
	void execute(StateContext* sc1, Player &player);
	void execute();
};


#endif